package cn.agrael.util;

import java.io.Serializable;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

/**
 * 用来存放常量的Map任何对该Map进行修改的操作都会抛出{@link UnsupportedOperationException}。
 * 
 * @author <a href="mailto:agraellee@gmail.com">Agrael·Lee</a>
 * @see ConstantUtils
 */
public class ConstantMap extends LinkedHashMap<String, String> implements Map<String, String>, Serializable {

	/** 版本号 */
	private static final long serialVersionUID = -1471755330345230245L;

	private int hash;

	/**
	 * 构造一个空的的 ConstantMap。
	 */
	ConstantMap() {

	}

	/**
	 * 使用一个 Map 的信息构造一个新的 ConstantMap。
	 * 
	 * @param map 用于构造 ConstantMap 的 Map。
	 */
	ConstantMap(Map<String, String> map) {
		for (Map.Entry<String, String> entry : map.entrySet()) {
			addAndOverride(entry.getKey(), entry.getValue());
		}
	}

	/**
	 * 添加一组常量印射，如果之前存在相同键的印射，则不作修改保留之前的印射关系。
	 * 
	 * @param key 键。
	 * @param value 常量。
	 */
	synchronized void add(String key, String value) {
		String v = get(key);
		if (v == null) {
			super.put(key, value);
		}
	}

	/**
	 * 添加一组常量印射，如果之前存在相同键的印射，用新的印射覆盖之前的印射。
	 * 
	 * @param key 键。
	 * @param value 常量。
	 */
	synchronized void addAndOverride(String key, String value) {
		super.put(key, value);
	}

	/**
	 * 返回键所对应的常量。
	 * 
	 * @param key 键，该键只支持{@link String}，除了{@link String}以外的类型都会抛出
	 *            IllegalArgumentException。
	 * @return 键所对应的常量。
	 * @throws IllegalArgumentException 当参数类型不为 String 时。
	 */
	@Override
	public String get(Object key) {
		if (!(key instanceof String)) {
			throw new IllegalArgumentException("该操作只支持[String]类型作为参数.");
		}
		return super.get(key);
	}

	/**
	 * 抛出 UnsupportedOperationException。
	 * 
	 * @throws UnsupportedOperationException 总是抛出。
	 */
	@Override
	public void clear() throws UnsupportedOperationException {
		throw new UnsupportedOperationException("不支持的操作.");
	}

	/**
	 * 抛出 UnsupportedOperationException。
	 * 
	 * @throws UnsupportedOperationException 总是抛出。
	 */
	@Override
	public String put(String key, String value) {
		throw new UnsupportedOperationException("不支持的操作.");
	}

	/**
	 * 抛出 UnsupportedOperationException。
	 * 
	 * @throws UnsupportedOperationException 总是抛出。
	 */
	@Override
	public void putAll(Map<? extends String, ? extends String> t) {
		throw new UnsupportedOperationException("不支持的操作.");
	}

	/**
	 * 抛出 UnsupportedOperationException。
	 * 
	 * @throws UnsupportedOperationException 总是抛出。
	 */
	@Override
	public String remove(Object key) {
		throw new UnsupportedOperationException("不支持的操作.");
	}

	/**
	 * 返回该Map的不可修改的映射关系的{@link Set}视图。
	 * 
	 * @return 该Map的不可修改的映射关系的{@link Set}视图。任何试图修改的操作都会抛出
	 *         {@link UnsupportedOperationException}。
	 */
	public Set<Entry<String, String>> entrySet() {
		return new ConstantEntrySet(super.entrySet());
	}

	@Override
	public int hashCode() {
		int result = this.hash;
		if (result == 0) {
			final int prime = 31;
			result = prime * result + super.hashCode();
			this.hash = result;
		}
		return result;
	}

	/**
	 * ConstantMap 所用到的 EntrySet ,该 Set 不允许任何修改。
	 * 
	 * @author <a href="mailto:agraellee@gmail.com">Agrael·Lee</a>
	 * 
	 */
	static class ConstantEntrySet extends AbstractSet<Entry<String, String>> implements Set<Entry<String, String>>, Serializable {

		/** 版本号 */
		private static final long serialVersionUID = -5220377271915968467L;

		private Set<Entry<String, String>> entrySet;

		private int size;

		ConstantEntrySet(Set<Entry<String, String>> entrySet) {
			this.size = entrySet.size();
			this.entrySet = entrySet;
		}

		@Override
		public Iterator<Entry<String, String>> iterator() {
			return new EntrySetIterator(this.entrySet.iterator());
		}

		@Override
		public int size() {
			return this.size;
		}

		@Override
		public boolean add(Entry<String, String> o) {
			throw new UnsupportedOperationException();
		}

		@Override
		public boolean remove(Object o) {
			throw new UnsupportedOperationException();
		}

		@Override
		public boolean addAll(Collection<? extends Entry<String, String>> coll) {
			throw new UnsupportedOperationException();
		}

		@Override
		public boolean removeAll(Collection<?> coll) {
			throw new UnsupportedOperationException();
		}

		@Override
		public boolean retainAll(Collection<?> coll) {
			throw new UnsupportedOperationException();
		}

		@Override
		public void clear() {
			throw new UnsupportedOperationException();
		}

		/**
		 * 用作 ConstantEntrySet 的不可修改 迭代器。
		 * 
		 * @author <a href="mailto:agraellee@gmail.com">Agrael·Lee</a>
		 * 
		 */
		static class EntrySetIterator implements Iterator<Entry<String, String>> {

			private Iterator<Entry<String, String>> iterator;

			EntrySetIterator(Iterator<Entry<String, String>> iterator) {
				this.iterator = iterator;
			}

			public boolean hasNext() {
				return this.iterator.hasNext();
			}

			public Entry<String, String> next() {
				return this.iterator.next();
			}

			public void remove() {
				throw new UnsupportedOperationException("不支持的操作.");
			}
		}
	}

}
